#include <cstring>
#include <iostream>
using namespace std;
extern "C" { // 指定函数是c语言函数，函数名不包含重载标注
// 引用ffmpeg头文件
#include <libavformat/avformat.h>
}
#ifdef main
#undef main
#endif // !main
void PrintErr(int err) {
  char buf[1024] = {0};
  av_strerror(err, buf, sizeof(buf) - 1);
  cerr << buf << endl;
}
#define CERR(no)                                                               \
  if (no != 0) {                                                               \
    PrintErr(no);                                                              \
    return -1;                                                                 \
  }

int main(int argc, char *argv[]) {
  av_log_set_level(AV_LOG_ERROR);
  const char *url = "v1080.mp4";
  AVFormatContext *ic = nullptr;
  int re = avformat_open_input(&ic, url,
                               nullptr, // 封装器格式，nullptr表示自动探测
                               nullptr); // 参数设置，rtsp需要设置
  CERR(re);
  re = avformat_find_stream_info(ic, nullptr);
  CERR(re);

  // av_find_best_stream();
  AVStream *as = nullptr;
  AVStream *vs = nullptr;
  for (int i = 0; i < ic->nb_streams; ++i) {
    if (ic->streams[i]->codecpar->codec_type ==
        AVMediaType::AVMEDIA_TYPE_AUDIO) {
      as = ic->streams[i];
      cout << "======音频=======" << endl;
      cout << "sample_rate:" << as->codecpar->sample_rate << endl;
    } else if (ic->streams[i]->codecpar->codec_type ==
               AVMediaType::AVMEDIA_TYPE_VIDEO) {
      vs = ic->streams[i];
      cout << "======视频=======" << endl;
      cout << "width:" << vs->codecpar->width << endl;
      cout << "height:" << vs->codecpar->height << endl;
    }
  }
  ////////////////////////////////////////////

  ////////////////////////////////////////////////////////////////////////////////////
  /// 解封装
  // 编码器上下文
  const char *out_url = "test_mux.mp4";
  AVFormatContext *ec = nullptr;
  re = avformat_alloc_output_context2(&ec, NULL, NULL,
                                      out_url // 根据文件名推测封装格式
  );
  CERR(re);
  // 添加视频流、音频流
  auto mvs = avformat_new_stream(ec, NULL); // 视频流
  auto mas = avformat_new_stream(ec, NULL); // 音频流

  // 打开输出IO
  re = avio_open(&ec->pb, out_url, AVIO_FLAG_WRITE);
  CERR(re);
  // 设置编码音视频流参数
  // ec->streams[0];
  // mvs->codecpar;//视频参数
  if (vs) {
    mvs->time_base = vs->time_base; // 时间基数与原视频一致
    // 从解封装复制参数
    avcodec_parameters_copy(mvs->codecpar, vs->codecpar);
  }

  if (as) {
    mas->time_base = as->time_base;
    // 从解封装复制参数
    avcodec_parameters_copy(mas->codecpar, as->codecpar);
  }
  // 写入文件头
  re = avformat_write_header(ec, NULL);
  CERR(re);
  // 打印信息，
  av_dump_format(ic, 0, url, false);
  ///////////////////////////////////////////////
  /// \brief begin_sec
  /// 截取10—20s
  double begin_sec = 10.0; // 截取开始时间
  double end_sec = 20.0;   // 截取结束时间
  long long begin_pts = 0;
  long long end_pts = 0;
  long long begin_audio_pts = 0;
  long long end_audio_pts = 0;
  // 换算成pts，换算成输入ic的pts
  if (vs && vs->time_base.den > 0) {
    // sec /timebase = pts
    // pts = sec/(num/den) = sec*den/num;
    double t = (double)vs->time_base.den / (double)vs->time_base.num;
    begin_pts = begin_sec * t;
    end_pts = end_sec * t;
  }
  if (as && as->time_base.den > 0) {
    double t = (double)as->time_base.den / (double)as->time_base.num;
    begin_audio_pts = begin_sec * t;
    end_audio_pts = end_sec * t;
  }
  // seek输入媒体问题 移动到第十秒的关键帧位置
  if (vs) {
    re = av_seek_frame(ic, vs->index, begin_pts,
                       AVSEEK_FLAG_FRAME | AVSEEK_FLAG_BACKWARD);
    CERR(re);
  }

  AVPacket pkt;
  for (;;) {
    re = av_read_frame(ic, &pkt);
    if (re == AVERROR_EOF) {
      break;
    }
    CERR(re);
    AVStream *in_stream = ic->streams[pkt.stream_index];
    AVStream *out_stream = nullptr;
    long long offset_pts = 0; // 偏移pts
    if (vs && pkt.stream_index == vs->index) {
      // 解码视频
      in_stream = vs;
      out_stream = mvs;
      // 超过20秒退出
      if (pkt.pts > end_pts) {
        av_packet_unref(&pkt);
        break;
      }
      offset_pts = begin_pts;
    } else if (as && pkt.stream_index == as->index) {
      // 解码视频
      in_stream = as;
      out_stream = mas;
      offset_pts = begin_audio_pts;
    }
    // 因为截取了，所以pts应该减去前面10秒,再调用av_rescale_q_rnd来确保a*bq/cq
    pkt.pts = av_rescale_q_rnd(pkt.pts - offset_pts, in_stream->time_base,
                               out_stream->time_base,
                               AVRounding(AV_ROUND_INF | AV_ROUND_PASS_MINMAX));
    pkt.dts = av_rescale_q_rnd(pkt.dts - offset_pts, in_stream->time_base,
                               out_stream->time_base,
                               AVRounding(AV_ROUND_INF | AV_ROUND_PASS_MINMAX));
    pkt.duration =
        av_rescale_q(pkt.duration, in_stream->time_base, out_stream->time_base);
    pkt.pos = -1;
    re = av_interleaved_write_frame(ec, &pkt);
    CERR(re);
    av_packet_unref(&pkt);
  }
  av_write_trailer(ec);
  avformat_close_input(&ic);
  return 0;
}
